home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / board / GNUChess4_0_58.lha / gnuchess-4.0 / src / new / checkbook.c < prev    next >
C/C++ Source or Header  |  1992-08-26  |  22KB  |  1,005 lines

  1. /*
  2.  * checkbook.c - Check a xboard game file or a gnuchess format book for
  3.  * illegal moves. Usage: checkbook [-x] file
  4.  *
  5.  * -x : read xboard game file otherwise read gnuchess book file
  6.  *
  7.  * Limitations: It checks the positions of all pieces of a castling move but
  8.  * does not check that any of the squares crossed is under control of the
  9.  * opponent and does not check that the king or rook have been previously
  10.  * moved. Take it as a TODO.
  11.  *
  12.  * Author M. McGann (mwm@hslrswi.hasler.ascom.ch)
  13.  *
  14.  * Copyright (c) 1992 Free Software Foundation
  15.  *
  16.  * This file is part of GNU CHESS.
  17.  *
  18.  * GNU Chess is free software; you can redistribute it and/or modify
  19.  * it under the terms of the GNU General Public License as published by
  20.  * the Free Software Foundation; either version 2, or (at your option)
  21.  * any later version.
  22.  *
  23.  * GNU Chess is distributed in the hope that it will be useful,
  24.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  * GNU General Public License for more details.
  27.  *
  28.  * You should have received a copy of the GNU General Public License
  29.  * along with GNU Chess; see the file COPYING.  If not, write to
  30.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  31.  */
  32. #include <stdio.h>
  33. #include "gnuchess.h"
  34.  
  35. #ifdef MSDOS
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <time.h>
  39. #undef RWA_ACC
  40. #undef WA_ACC
  41. #define RWA_ACC "rb"
  42. #define WA_ACC "w+b"
  43. #else
  44. #undef RWA_ACC
  45. #undef WA_ACC
  46. #define RWA_ACC "r"
  47. #define WA_ACC "w+"
  48. #include <sys/param.h>
  49. #include <sys/types.h>
  50. #include <sys/times.h>
  51. #endif /* MSDOS */
  52. FILE *fd;
  53.  
  54. #define truescore 0x0001
  55. #define lowerbound 0x0002
  56. #define upperbound 0x0004
  57. #define kingcastle 0x0008
  58. #define queencastle 0x0010
  59. const short otherside[3] =
  60. {black, white, neutral};
  61.  
  62. struct GameRec GameList[512];
  63. char mvstr[4][6];
  64. long i, j;
  65. short int ep;
  66. int r, c;
  67. char line[128];
  68. char *l;
  69. short int board[64];
  70. short int color[64];
  71. short int GameCnt;
  72. int from, to;
  73. char *InPtr;
  74. int ckcastld[2];
  75. short int epsquare = -1;
  76. int ok;
  77. int mvptr = 0;
  78. struct leaf Tree[256];
  79. int endflag;
  80. int xflag = false;
  81. char mvflag;
  82. char MOVE[256];
  83.  
  84. /* .... MOVE GENERATION VARIABLES AND INITIALIZATIONS .... */
  85.  
  86. const short kingP[3] =
  87. {4, 60, 0};
  88. const short Stboard[64] =
  89. {rook, knight, bishop, queen, king, bishop, knight, rook,
  90.  pawn, pawn, pawn, pawn, pawn, pawn, pawn, pawn,
  91.  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  92.  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  93.  pawn, pawn, pawn, pawn, pawn, pawn, pawn, pawn,
  94.  rook, knight, bishop, queen, king, bishop, knight, rook};
  95. const short Stcolor[64] =
  96. {white, white, white, white, white, white, white, white,
  97.  white, white, white, white, white, white, white, white,
  98.  neutral, neutral, neutral, neutral, neutral, neutral, neutral, neutral,
  99.  neutral, neutral, neutral, neutral, neutral, neutral, neutral, neutral,
  100.  neutral, neutral, neutral, neutral, neutral, neutral, neutral, neutral,
  101.  neutral, neutral, neutral, neutral, neutral, neutral, neutral, neutral,
  102.  black, black, black, black, black, black, black, black,
  103.  black, black, black, black, black, black, black, black};
  104. short board[64], color[64];
  105.  
  106. /*
  107.  * nextpos[piece][from-square] , nextdir[piece][from-square] gives vector of
  108.  * positions reachable from from-square in ppos with piece such that the
  109.  * sequence    ppos = nextpos[piece][from-square]; pdir =
  110.  * nextdir[piece][from-square]; u = ppos[sq]; do { u = ppos[u]; if(color[u]
  111.  * != neutral) u = pdir[u]; } while (sq != u); will generate the sequence of
  112.  * all squares reachable from sq.
  113.  *
  114.  * If the path is blocked u = pdir[sq] will generate the continuation of the
  115.  * sequence in other directions.
  116.  */
  117.  
  118. unsigned char nextpos[8][64][64];
  119. unsigned char nextdir[8][64][64];
  120.  
  121. /*
  122.  * ptype is used to separate white and black pawns, like this; ptyp =
  123.  * ptype[side][piece] piece can be used directly in nextpos/nextdir when
  124.  * generating moves for pieces that are not black pawns.
  125.  */
  126. const short ptype[2][8] =
  127. {
  128.   no_piece, pawn, knight, bishop, rook, queen, king, no_piece,
  129.   no_piece, bpawn, knight, bishop, rook, queen, king, no_piece};
  130.  
  131. /* data used to generate nextpos/nextdir */
  132. static const short direc[8][8] =
  133. {
  134.   0, 0, 0, 0, 0, 0, 0, 0,
  135.   10, 9, 11, 0, 0, 0, 0, 0,
  136.   8, -8, 12, -12, 19, -19, 21, -21,
  137.   9, 11, -9, -11, 0, 0, 0, 0,
  138.   1, 10, -1, -10, 0, 0, 0, 0,
  139.   1, 10, -1, -10, 9, 11, -9, -11,
  140.   1, 10, -1, -10, 9, 11, -9, -11,
  141.   -10, -9, -11, 0, 0, 0, 0, 0};
  142. static const short max_steps[8] =
  143. {0, 2, 1, 7, 7, 7, 1, 2};
  144. static const short nunmap[120] =
  145. {
  146.   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  147.   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  148.   -1, 0, 1, 2, 3, 4, 5, 6, 7, -1,
  149.   -1, 8, 9, 10, 11, 12, 13, 14, 15, -1,
  150.   -1, 16, 17, 18, 19, 20, 21, 22, 23, -1,
  151.   -1, 24, 25, 26, 27, 28, 29, 30, 31, -1,
  152.   -1, 32, 33, 34, 35, 36, 37, 38, 39, -1,
  153.   -1, 40, 41, 42, 43, 44, 45, 46, 47, -1,
  154.   -1, 48, 49, 50, 51, 52, 53, 54, 55, -1,
  155.   -1, 56, 57, 58, 59, 60, 61, 62, 63, -1,
  156.   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  157.   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
  158.  
  159. int InitFlag = false;
  160.  
  161.  
  162. void
  163. DISP (void)
  164. {
  165.  
  166.   short r, c, l;
  167.  
  168.   if (true)
  169.     {
  170.       printf ("\n");
  171.       for (r = 7; r >= 0; r--)
  172.     {
  173.       printf ("%c ", Rxx[r]);
  174.       for (c = 0; c <= 7; c++)
  175.         {
  176.           l = locn (r, c);
  177.           if (color[l] == neutral)
  178.         printf (" -");
  179.           else if (color[l] == white)
  180.         printf (" %c", Qxx[board[l]]);
  181.           else
  182.         printf (" %c", Pxx[board[l]]);
  183.         }
  184.       printf ("\n");
  185.     }
  186.       printf ("   a b c d e f g h\n");
  187.     }
  188. }
  189.  
  190. int
  191. castle (short int side, short int kf, short int kt, short int iop)
  192.  
  193. /* Make or Unmake a castling move. */
  194.  
  195. {
  196.   register short rf, rt, xside;
  197.  
  198.   xside = otherside[side];
  199.   if (kt > kf)
  200.     {
  201.       rf = kf + 3;
  202.       rt = kt - 1;
  203.     }
  204.   else
  205.     {
  206.       rf = kf - 4;
  207.       rt = kt + 1;
  208.     }
  209.   if (kf != kingP[side] ||
  210.       board[kf] != king ||
  211.       board[rf] != rook ||
  212.       color[kt] != neutral ||
  213.       color[rt] != neutral ||
  214.       color[kt - 1] != neutral)
  215.     return (false);
  216.   else
  217.     return (true);
  218. }
  219.  
  220. void
  221. Initialize_moves (void)
  222.  
  223. /*
  224.  * This procedure pre-calculates all moves for every piece from every square.
  225.  * This data is stored in nextpos/nextdir and used later in the move
  226.  * generation routines.
  227.  */
  228.  
  229. {
  230.   short ptyp, po, p0, d, di, s, delta;
  231.   unsigned char *ppos, *pdir;
  232.   short dest[8][8];
  233.   short steps[8];
  234.   short sorted[8];
  235.  
  236.   for (ptyp = 0; ptyp < 8; ptyp++)
  237.     for (po = 0; po < 64; po++)
  238.       for (p0 = 0; p0 < 64; p0++)
  239.     {
  240.       nextpos[ptyp][po][p0] = (unsigned char) po;
  241.       nextdir[ptyp][po][p0] = (unsigned char) po;
  242.     }
  243.   for (ptyp = 1; ptyp < 8; ptyp++)
  244.     for (po = 21; po < 99; po++)
  245.       if (nunmap[po] >= 0)
  246.     {
  247.       ppos = nextpos[ptyp][nunmap[po]];
  248.       pdir = nextdir[ptyp][nunmap[po]];
  249.       /* dest is a function of direction and steps */
  250.       for (d = 0; d < 8; d++)
  251.         {
  252.           dest[d][0] = nunmap[po];
  253.           delta = direc[ptyp][d];
  254.           if (delta != 0)
  255.         {
  256.           p0 = po;
  257.           for (s = 0; s < max_steps[ptyp]; s++)
  258.             {
  259.               p0 = p0 + delta;
  260.  
  261.               /*
  262.                * break if (off
  263.                * board) or (pawns
  264.                * only move two
  265.                * steps from home
  266.                * square)
  267.                */
  268.               if ((nunmap[p0] < 0) || (((ptyp == pawn) || (ptyp == bpawn))
  269.                            && ((s > 0) && ((d > 0) || (Stboard[nunmap[po]] != pawn)))))
  270.             break;
  271.               else
  272.             dest[d][s] = nunmap[p0];
  273.             }
  274.         }
  275.           else
  276.         s = 0;
  277.  
  278.           /*
  279.            * sort dest in number of steps order
  280.            * currently no sort is done due to
  281.            * compability with the move
  282.            * generation order in old gnu chess
  283.            */
  284.           steps[d] = s;
  285.           for (di = d; s > 0 && di > 0; di--)
  286.         if (steps[sorted[di - 1]] == 0)    /* should be: < s */
  287.           sorted[di] = sorted[di - 1];
  288.         else
  289.           break;
  290.           sorted[di] = d;
  291.         }
  292.  
  293.       /*
  294.        * update nextpos/nextdir, pawns have two
  295.        * threads (capture and no capture)
  296.        */
  297.       p0 = nunmap[po];
  298.       if (ptyp == pawn || ptyp == bpawn)
  299.         {
  300.           for (s = 0; s < steps[0]; s++)
  301.         {
  302.           ppos[p0] = (unsigned char) dest[0][s];
  303.           p0 = dest[0][s];
  304.         }
  305.           p0 = nunmap[po];
  306.           for (d = 1; d < 3; d++)
  307.         {
  308.           pdir[p0] = (unsigned char) dest[d][0];
  309.           p0 = dest[d][0];
  310.         }
  311.         }
  312.       else
  313.         {
  314.           pdir[p0] = (unsigned char) dest[sorted[0]][0];
  315.           for (d = 0; d < 8; d++)
  316.         for (s = 0; s < steps[sorted[d]]; s++)
  317.           {
  318.             ppos[p0] = (unsigned char) dest[sorted[d]][s];
  319.             p0 = dest[sorted[d]][s];
  320.             if (d < 7)
  321.               pdir[p0] = (unsigned char) dest[sorted[d + 1]][0];
  322.  
  323.             /*
  324.              * else is already
  325.              * initialized
  326.              */
  327.           }
  328.         }
  329.     }
  330. }
  331.  
  332. #define Link(from,to,flag,s) \
  333. {\
  334.    node->f = from; node->t = to;\
  335.      node->reply = 0;\
  336.        node->flags = flag;\
  337.      node->score = s;\
  338.        ++node;\
  339.          ++mvptr;\
  340.          }
  341.  
  342. inline void
  343. LinkMove (short int ply,
  344.       short int f,
  345.       short int t,
  346.       short int flag,
  347.       short int xside)
  348.  
  349. /*
  350.  * Add a move to the tree.  Assign a bonus to order the moves as follows: 1.
  351.  * Principle variation 2. Capture of last moved piece 3. Other captures
  352.  * (major pieces first) 4. Killer moves 5.
  353.  */
  354.  
  355. {
  356.   register short s;
  357.   register unsigned short mv;
  358.   register struct leaf *node;
  359.  
  360.   s = 0;
  361.   node = &Tree[mvptr];
  362.   mv = (f << 8) | t;
  363.   if (row (t) == 0 || row (t) == 7)
  364.     {
  365.       flag |= promote;
  366.       Link (f, t, flag | queen, s - 20000);
  367.       Link (f, t, flag | knight, s - 20000);
  368.       Link (f, t, flag | rook, s - 20000);
  369.       flag |= bishop;
  370.     }
  371.   else if (row (t) == 1 || row (t) == 6)
  372.     {
  373.       flag |= pwnthrt;
  374.     }
  375.   Link (f, t, flag, s - 20000);
  376. }
  377.  
  378.  
  379. void
  380. GenMoves (register short int ply, register short int sq, short int side, short int xside)
  381.  
  382. /*
  383.  * Generate moves for a piece. The moves are taken from the precalulated
  384.  * array nextpos/nextdir. If the board is free, next move is choosen from
  385.  * nextpos else from nextdir.
  386.  */
  387.  
  388. {
  389.   register short u, piece;
  390.   register unsigned char *ppos, *pdir;
  391.  
  392.   mvptr = 0;
  393.   piece = board[sq];
  394.   ppos = nextpos[ptype[side][piece]][sq];
  395.   pdir = nextdir[ptype[side][piece]][sq];
  396.   if (piece == pawn)
  397.     {
  398.       u = ppos[sq];        /* follow no captures thread */
  399.       if (color[u] == neutral)
  400.     {
  401.       LinkMove (ply, sq, u, 0, xside);
  402.       u = ppos[u];
  403.       if (color[u] == neutral)
  404.         LinkMove (ply, sq, u, 0, xside);
  405.     }
  406.       u = pdir[sq];        /* follow captures thread */
  407.       if (color[u] == xside)
  408.     LinkMove (ply, sq, u, capture, xside);
  409.       else if (u == epsquare)
  410.     LinkMove (ply, sq, u, capture | epmask, xside);
  411.       u = pdir[u];
  412.       if (color[u] == xside)
  413.     LinkMove (ply, sq, u, capture, xside);
  414.       else if (u == epsquare)
  415.     LinkMove (ply, sq, u, capture | epmask, xside);
  416.  
  417.     }
  418.   else
  419.     {
  420.       u = ppos[sq];
  421.       do
  422.     {
  423.       if (color[u] == neutral)
  424.         {
  425.           LinkMove (ply, sq, u, 0, xside);
  426.           u = ppos[u];
  427.         }
  428.       else
  429.         {
  430.           if (color[u] == xside)
  431.         LinkMove (ply, sq, u, capture, xside);
  432.           u = pdir[u];
  433.         }
  434.       } while (u != sq);
  435.     }
  436. }
  437. void
  438. skip ()
  439. {
  440.   while (*InPtr != ' ' && *InPtr != '\n')
  441.     InPtr++;
  442.   while (*InPtr == ' ' && *InPtr != '\n')
  443.     InPtr++;
  444. }
  445. void
  446. skipb ()
  447. {
  448.   while (*InPtr == ' ')
  449.     InPtr++;
  450. }
  451. int
  452. parser (char *f, int side, short *flags)
  453. {
  454.   int c1, r1, c2, r2;
  455.  
  456.   *flags = 0;
  457.  
  458.   if (f[4] == 'o')
  459.     if (side == black)
  460.       return 0x3C3A;
  461.     else
  462.       return 0x0402;
  463.   else if (f[0] == 'o')
  464.     if (side == black)
  465.       return 0x3C3E;
  466.     else
  467.       return 0x0406;
  468.   else
  469.     {
  470.       c1 = f[0] - 'a';
  471.       r1 = f[1] - '1';
  472.       c2 = f[2] - 'a';
  473.       r2 = f[3] - '1';
  474.       if ((f[4] != ' ') && (f[4] != '\n') && f[4] != '?')
  475.     {
  476.       /* promotion */
  477.       for (i = 0; i < sizeof (Qxx); i++)
  478.         if (f[4] == Qxx[i])
  479.           {
  480.         *flags = (i | promote);
  481.         break;
  482.           }
  483.     }
  484.       return (locn (r1, c1) << 8) | locn (r2, c2);
  485.     }
  486.   /*NOTREACHED*/
  487. }
  488.  
  489. void
  490. algbr (short int f, short int t, short int flag)
  491.  
  492.  
  493. /*
  494.  * Generate move strings in different formats.
  495.  */
  496.  
  497. {
  498.   int m3p;
  499.  
  500.   if (f != t)
  501.     {
  502.       /* algebraic notation */
  503.       mvstr[0][0] = Cxx[column (f)];
  504.       mvstr[0][1] = Rxx[row (f)];
  505.       mvstr[0][2] = Cxx[column (t)];
  506.       mvstr[0][3] = Rxx[row (t)];
  507.       mvstr[0][4] = mvstr[3][0] = '\0';
  508.       if (((mvstr[1][0] = Pxx[board[f]]) == 'P') || (flag & promote))
  509.     {
  510.       if (mvstr[0][0] == mvstr[0][2])    /* pawn did not eat */
  511.         {
  512.           mvstr[2][0] = mvstr[1][0] = mvstr[0][2];    /* to column */
  513.           mvstr[2][1] = mvstr[1][1] = mvstr[0][3];    /* to row */
  514.           m3p = 2;
  515.         }
  516.       else
  517.         /* pawn ate */
  518.         {
  519.           mvstr[2][0] = mvstr[1][0] = mvstr[0][0];    /* column */
  520.           mvstr[2][1] = mvstr[1][1] = mvstr[0][2];    /* to column */
  521.           mvstr[2][2] = mvstr[0][3];
  522.           m3p = 3;        /* to row */
  523.         }
  524.       if (flag & promote)
  525.         {
  526.           mvstr[0][4] = mvstr[1][2] = mvstr[2][m3p] = Qxx[flag & pmask];
  527.           mvstr[1][3] = mvstr[2][m3p + 1] = mvstr[0][5] = '\0';
  528. #ifdef CHESSTOOL
  529.           mvstr[3][0] = mvstr[0][0];    /* Allow e7e8 for
  530.                          * chesstool */
  531.           mvstr[3][1] = mvstr[0][1];
  532.           mvstr[3][2] = mvstr[0][2];
  533.           mvstr[3][3] = mvstr[0][3];
  534.           mvstr[3][4] = '\0';
  535. #endif
  536.         }
  537.       mvstr[2][m3p] = mvstr[1][2] = '\0';
  538.     }
  539.       else
  540.     /* not a pawn */
  541.     {
  542.       mvstr[2][0] = mvstr[1][0];
  543.       mvstr[2][1] = mvstr[0][1];
  544.       mvstr[2][2] = mvstr[1][1] = mvstr[0][2];    /* to column */
  545.       mvstr[2][3] = mvstr[1][2] = mvstr[0][3];    /* to row */
  546.       mvstr[2][4] = mvstr[1][3] = '\0';
  547.       strcpy (mvstr[3], mvstr[2]);
  548.       mvstr[3][1] = mvstr[0][0];
  549.       if (flag & cstlmask)
  550.         {
  551.           if (t > f)
  552.         {
  553.           strcpy (mvstr[1], "o-o");
  554.           strcpy (mvstr[2], "O-O");
  555.         }
  556.           else
  557.         {
  558.           strcpy (mvstr[1], "o-o-o");
  559.           strcpy (mvstr[2], "O-O-O");
  560.         }
  561.         }
  562.     }
  563.     }
  564.   else
  565.     mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = '\0';
  566. }
  567. char fb[256];
  568. int
  569. checkend (char *p)
  570. {
  571.   int j, l;
  572.   char *q;
  573.   if (xflag)
  574.     {
  575.       if (!strcmp (MOVE, "White"))
  576.     return true;
  577.       if (!strcmp (MOVE, "Black"))
  578.     return true;
  579.       if (!strcmp (MOVE, "draw"))
  580.     return true;
  581.     }
  582.   for (q = MOVE; *p != ' ' && *p != '\t' && *p != '\n'; p++)
  583.     {
  584.       *q++ = *p;
  585.     } *q = '\0';
  586.   l = strlen (MOVE);
  587.   if (l == 2)
  588.     {
  589.       j = MOVE[1] - 'a';
  590.       if (j < 0 || j > 8)
  591.     {
  592.       printf ("illegal move %s\n", fb);
  593.       exit (1);
  594.     }
  595.       j = MOVE[2] - '0';
  596.       if (j < 0 || j > 8)
  597.     {
  598.       printf ("illegal move %s\n", fb);
  599.       exit (1);
  600.     }
  601.       return false;
  602.     }
  603.   else if (l == 3)
  604.     {
  605.       if (!strcmp (MOVE, "o-o"))
  606.     return false;
  607.       for (j = 0; j < sizeof (Qxx); j++)
  608.     if (MOVE[0] == Qxx[j])
  609.       {
  610.         return false;
  611.       }
  612.       j = MOVE[1] - 'a';
  613.       if (j < 0 || j > 8)
  614.     {
  615.       printf ("illegal move %s\n", fb);
  616.       exit (1);
  617.     }
  618.       j = MOVE[2] - '0';
  619.       if (j < 0 || j > 8)
  620.     {
  621.       printf ("illegal move %s\n", fb);
  622.       exit (1);
  623.     }
  624.       return false;
  625.     }
  626.   else if (l == 5)
  627.     {
  628.       if (!strcmp (MOVE, "o-o-o"))
  629.     return false;
  630.     }
  631.   else if (l != 4)
  632.     {
  633.       printf ("illegal move %s\n", fb);
  634.       exit (1);
  635.     }
  636.   /* check for a legal move */
  637.   j = MOVE[0] - 'a';
  638.   if (j < 0 || j > 8)
  639.     {
  640.       printf ("illegal move %s\n", fb);
  641.       exit (1);
  642.     }
  643.   j = MOVE[1] - '0';
  644.   if (j < 0 || j > 8)
  645.     {
  646.       printf ("illegal move %s\n", fb);
  647.       exit (1);
  648.     }
  649.   j = MOVE[2] - 'a';
  650.   if (j < 0 || j > 8)
  651.     {
  652.       printf ("illegal move %s\n", fb);
  653.       exit (1);
  654.     }
  655.   j = MOVE[3] - '0';
  656.   if (j < 0 || j > 8)
  657.     {
  658.       printf ("illegal move %s\n", fb);
  659.       exit (1);
  660.     }
  661.   if (l == 4)
  662.     return false;
  663.   if (MOVE[4] == '?')
  664.     return false;
  665.   if (MOVE[4] == 'p')
  666.     {
  667.       printf ("illegal promotion??? %s", fb);
  668.       exit (1);
  669.     }
  670.   for (j = 0; j < sizeof (Qxx); j++)
  671.     if (MOVE[4] == Qxx[j])
  672.       {
  673.     return false;
  674.       }
  675.   printf ("illegal promotion??? %s", fb);
  676.   exit (1);
  677.   return true;
  678. }
  679.  
  680. char title[256];
  681. int firsttime = true;
  682.  
  683. GetGame ()
  684. {
  685.   struct GameRec *g;
  686.   int side = white;
  687.  
  688.   if (firsttime)
  689.     {
  690.       if (xflag)
  691.     {
  692.       fgets (fb, 256, fd);
  693.       fgets (fb, 256, fd);
  694.       fgets (fb, 256, fd);
  695.     }
  696.       fgets (fb, 256, fd);
  697.       firsttime = false;
  698.     }
  699.   do
  700.     {
  701.       if ((fb[0] == '!') || (fb[0] == '#'))
  702.     {
  703.       if (!GameCnt)
  704.         {
  705.           strcpy (title, fb);
  706.           continue;
  707.         }
  708.       else
  709.         return 0;
  710.     }
  711.       InPtr = fb;
  712.       skipb ();
  713.       if (*InPtr == '\n')
  714.     continue;
  715.       if (isdigit (*InPtr))
  716.     {
  717.       skip ();
  718.       if (*InPtr == '\n')
  719.         continue;
  720.     }
  721.       if (checkend (InPtr))
  722.     {
  723.       if (GameCnt)
  724.         return 0;
  725.       else
  726.         {
  727.           printf ("No moves???\n");
  728.           exit (1);
  729.         }
  730.     }
  731.       ++GameCnt;
  732.       g = &GameList[GameCnt];
  733.       g->gmove = parser (InPtr, side, &(g->flags));
  734.       skip ();
  735.       if (*InPtr == '\n')
  736.     continue;
  737.       if (checkend (InPtr))
  738.     {
  739.       if (GameCnt)
  740.         return 0;
  741.       else
  742.         {
  743.           printf ("No moves???\n");
  744.           exit (1);
  745.         }
  746.     }
  747.       ++GameCnt;
  748.       side = otherside[side];
  749.       g = &GameList[GameCnt];
  750.       g->gmove = parser (InPtr, side, &(g->flags));
  751.       side = otherside[side];
  752.  
  753.   } while (fgets (fb, 256, fd) != NULL);
  754.   return -1;
  755. }
  756. short int xside, side;
  757. int
  758. getboard (int mvno)
  759.  
  760. {
  761.   register short int f, t;
  762.   short int rf, rt;
  763.   unsigned short mv;
  764.  
  765.  
  766.   /* now update the board and hash values */
  767.  
  768.   /*
  769.    * should really check the moves as we do this, but???
  770.    */
  771.   mv = GameList[mvno].gmove;
  772.   f = mv >> 8 & 0x7F;
  773.   t = mv & 0xFF;
  774.   /* can only capture other side */
  775.   if (board[t] != no_piece)
  776.     {
  777.       if (color[t] != xside)
  778.     {
  779.       algbr (f, t, 0);
  780.       printf ("\nIllegal move - %d %s \n", mvno, mvstr);
  781.     }
  782.     }
  783.   /* there must be a piece to move */
  784.   if (board[f] == no_piece || color[f] != side)
  785.     {
  786.       algbr (f, t, 0);
  787.       printf ("\nIllegal move + %d %s \n", mvno, mvstr);
  788.     }
  789.   /* is it EnPassant */
  790.  
  791.   if (board[f] == pawn && board[t] == no_piece)
  792.     {
  793.       if ((row (f) == 3 &&
  794.        row (t) == 2) || (row (f) == 4 && row (t) == 5))
  795.     {
  796.       if (column (t) != column (f))
  797.         {
  798.           ep = t + ((t > f) ? -8 : 8);
  799.           if (board[ep] == pawn && color[ep] == xside)
  800.         {
  801.           mvflag = 'e';
  802.           board[ep] = no_piece;
  803.           color[ep] = neutral;
  804.         }
  805.         }
  806.     }
  807.     }
  808.   board[t] = board[f];
  809.   color[t] = color[f];
  810.   color[f] = neutral;
  811.   board[f] = no_piece;
  812.   /* castle moves */
  813.   if ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE))
  814.     {
  815.  
  816.       if (t > f)
  817.     {
  818.       rf = f + 3;
  819.       rt = t - 1;
  820.     }
  821.       else
  822.     {
  823.       rf = f - 4;
  824.       rt = t + 1;
  825.     }
  826.       if ((board[t] == king && color[t] == side) && (board[rf] == rook) && (color[rf] == side))
  827.     {
  828.       mvflag = 'c';
  829.       board[rt] = rook;
  830.       color[rt] = side;
  831.       board[rf] = no_piece;
  832.       color[rf] = neutral;
  833.       ckcastld[side] = true;
  834.     }
  835.     }
  836.   else if (GameList[i].flags & promote)
  837.     {
  838.       board[t] = GameList[i].flags & pmask;
  839.       color[t] = side;
  840.     }
  841. }
  842.  
  843. int
  844. main (int argc, char **argv)
  845. {
  846.   int from, to;
  847.   unsigned short int mv;
  848.   int start, end;
  849.   int ii, kf, jj;
  850.   int filearg = 1;
  851.  
  852.   Initialize_moves ();
  853.  
  854.   if ((argc < 2) || (argc > 3))
  855.     {
  856.       printf ("Usage: checkbook file \n");
  857.       exit (1);
  858.     }
  859.   if (argc == 3)
  860.     {
  861.       if (strcmp (argv[1], "-x"))
  862.     {
  863.       printf ("illegal flag %s\n", argv[1]);
  864.       exit (1);
  865.     }
  866.       xflag = true;
  867.       filearg = 2;
  868.     }
  869.   if ((fd = fopen (argv[filearg], RWA_ACC)) == NULL)
  870.     exit (1);
  871.   endflag = 0;
  872.   while (true)
  873.     {
  874.       if (endflag < 0)
  875.     exit (0);
  876.       start = end = 0;
  877.       ckcastld[0] = ckcastld[1] = false;
  878.  
  879.       side = white;
  880.       xside = black;
  881.       for (i = 0; i < 64; i++)
  882.     {
  883.       board[i] = Stboard[i];
  884.       color[i] = Stcolor[i];
  885.     }
  886.       i = 1;
  887.       GameCnt = 0;
  888.       while (GameCnt == 0)
  889.     {
  890.       if ((endflag = GetGame ()) < 0)
  891.         if (!GameCnt)
  892.           exit (0);
  893.     }
  894.       printf ("-->%s %d\n", title, GameCnt);
  895.       start = 1;
  896.       end = GameCnt + 1;
  897.       side = white;
  898.       xside = black;
  899.       for (i = 1; i < end; i++)
  900.     {
  901.       mvflag = ' ';
  902.       mv = GameList[i].gmove;
  903.       from = mv >> 8 & 0x7F;
  904.       to = mv & 0x7F;
  905.       algbr (from, to, 0);
  906.  
  907.       GenMoves (0, from, side, xside);
  908.       if (!ckcastld[side] && board[from] == king && color[from] == side)
  909.         {
  910.           if (castle (side, from, from + 2, 0))
  911.         {
  912.           LinkMove (0, from, from + 2, cstlmask, xside);
  913.         }
  914.           if (castle (side, from, from - 2, 0))
  915.         {
  916.           LinkMove (0, from, from - 2, cstlmask, xside);
  917.         }
  918.         }
  919.       ok = false;
  920.       for (ii = 0; ii < mvptr; ii++)
  921.         {
  922.           if (from == Tree[ii].f && to == Tree[ii].t)
  923.         {
  924.           ok = true;
  925.           break;
  926.         }
  927.         }
  928.       if (!ok)
  929.         {
  930.           algbr (from, to, 0);
  931.           printf ("\nIllegal move %s\n", mvstr);
  932.           for (ii = 0; ii < mvptr; ii++)
  933.         {
  934.           algbr (Tree[ii].f, Tree[ii].t, 0);
  935.           printf (" %s\n", mvstr);
  936.         }
  937.           DISP ();
  938.           exit (1);
  939.         }
  940.       getboard (i);
  941.       if (side)
  942.         printf ("%s%c\n", mvstr, mvflag);
  943.       else
  944.         {
  945.           printf ("%d. ", 1 + ((i - 1) / 2));
  946.           printf ("%s%c  ", mvstr, mvflag);
  947.         }
  948.       if (board[to] == pawn)
  949.         if (to - from == 16)
  950.           epsquare = from + 8;
  951.         else if (from - to == 16)
  952.           epsquare = from - 8;
  953.         else
  954.           epsquare = -1;
  955.       kf = -1;
  956.       for (ii = 0; ii < 64; ii++)
  957.         {
  958.           if ((board[ii] == king) && (color[ii] == side))
  959.         {
  960.           kf = ii;
  961.           break;
  962.         }
  963.         }
  964.       if (kf < 0)
  965.         {
  966.           printf ("Badnews: you have no king\n");
  967.           DISP ();
  968.           exit (1);
  969.  
  970.         }
  971.       for (ii = 0; ii < 64; ii++)
  972.         {
  973.           if (color[ii] == xside)
  974.         {
  975.           mvptr = 0;
  976.           GenMoves (0, ii, xside, side);
  977.           for (jj = 0; jj < mvptr; jj++)
  978.             {
  979.               if (Tree[jj].t == kf)
  980.             {
  981.  
  982.               printf ("Badnews: you are in check\n");
  983.               printf ("king is at %c%c\n", Cxx[column (kf)], Rxx[row (kf)]);
  984.               algbr (Tree[jj].f, Tree[jj].t, 0);
  985.               printf ("move is %s\n", mvstr);
  986.               DISP ();
  987.               exit (1);
  988.             }
  989.             }
  990.         }
  991.         }
  992.       xside = side;
  993.       side = otherside[side];
  994.     }
  995.       printf ("\n\n");
  996.       if (xflag)
  997.     {
  998.       printf ("Final position:\n\n");
  999.       DISP ();
  1000.       exit (0);
  1001.     }
  1002.     }
  1003.   /*NOTREACHED*/
  1004. }
  1005.